/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is dual-licensed under either the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree or the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree. You may select, at your option, one of the
 * above-listed licenses.
 */

//! Generate source file containing buck2/prelude tree with contents.

use std::io;
use std::path::Path;

fn main() {
    imp().unwrap();
}

fn imp() -> io::Result<()> {
    let out_path = std::env::var_os("OUT_DIR").unwrap();
    let include_file = Path::new(&out_path).join("include.rs");
    let manifest_path = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
    let prelude_path = Path::new(&manifest_path)
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .join("prelude");

    // Self-check.
    assert!(prelude_path.join("prelude.bzl").exists());

    println!("cargo:rerun-if-changed={}", prelude_path.display());

    write_include_file(&prelude_path, std::fs::File::create(&include_file)?)?;

    Ok(())
}

fn as_unix_like(path: &Path) -> String {
    path.to_str().unwrap().replace('\\', "/")
}

fn write_include_file(prelude: &Path, mut include_file: impl io::Write) -> io::Result<()> {
    #[allow(clippy::write_literal)]
    writeln!(include_file, "// {}generated by crate build.rs", "@")?;

    writeln!(
        include_file,
        "pub(crate) const DATA: &[crate::BundledFile] = &["
    )?;

    for res in walkdir::WalkDir::new(prelude) {
        let entry = res.map_err(|e| e.into_io_error().unwrap())?;
        if !entry.file_type().is_file() {
            continue;
        }

        writeln!(include_file, "crate::BundledFile {{")?;
        writeln!(
            include_file,
            "  path: r\"{}\",",
            as_unix_like(entry.path().strip_prefix(prelude).unwrap())
        )?;
        writeln!(
            include_file,
            "  contents: include_bytes!(r\"{}\"),",
            entry.path().display()
        )?;

        let exec_bit;
        #[cfg(unix)]
        {
            use std::os::unix::fs::MetadataExt;
            exec_bit = entry.metadata()?.mode() & 0o111 != 0;
        }
        #[cfg(not(unix))]
        {
            exec_bit = false;
        }

        writeln!(include_file, "  is_executable: {exec_bit},")?;
        writeln!(include_file, "}},")?;
    }

    writeln!(include_file, "];")?;
    Ok(())
}
